package com.guapi.service;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.guapi.dao.Role;
import com.guapi.dao.User;
import com.guapi.exception.SelfException;
import com.guapi.mapper.wrapper.SelfQueryWrapper;
import com.guapi.security.UserDetailImpl;
import com.guapi.util.BaseConstant;
import com.guapi.util.RedisUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author 瓜皮哦
 */
@Service
public class UserService extends SelfBaseService<User> implements UserDetailsService {
    //@Autowired
    //private UserMapper userMapper;

    @Autowired
    @Lazy
    private AuthenticationManager authenticationManager;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private AuthService authService;

    @Autowired
    private MenuService menuService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RoleService roleService;

    public User doLogin(User user) {
        UsernamePasswordAuthenticationToken token = null;
        try {
            if (user.getAccount() != null) {
                token = new UsernamePasswordAuthenticationToken(user.getAccount(), user.getPassword());
            } else if (user.getEmail() != null) {
                token = new UsernamePasswordAuthenticationToken(user.getEmail(), user.getPassword());
            }
            Authentication authenticate = authenticationManager.authenticate(token);
            UserDetailImpl userDetail = (UserDetailImpl) authenticate.getPrincipal();
            user = userDetail.getUser();
            judgeUser(user);
            String redisKey = RedisUtil.getUserKey(String.valueOf(user.getId()));
            redisTemplate.opsForValue().set(redisKey, userDetail);
            redisTemplate.expire(redisKey, RedisUtil.TOKEN_EXPIRE_DATE, TimeUnit.MILLISECONDS);
        } catch (Exception e) {
            throw new SelfException("403", e);
        }
        user = getOne(user);
        return user;
    }

    public User saveUser(User user, boolean judgeEdit) {
        if (judgeEdit) {
            if (user.getPassword() != null) {
                user.setPassword(passwordEncoder.encode(user.getPassword()));
            }
            saveOrUpdate(user);
            return user;
        } else {
            User dbUser = new User();
            dbUser.setEmail(user.getEmail() == null ? null : user.getEmail());
            dbUser.setAccount(user.getAccount() == null ? null : user.getAccount());
            //判断数据库中是否已经存在
            List<User> userList = getByConditions(dbUser);
            //如果不存在，走添加逻辑
            if (CollectionUtil.isEmpty(userList)) {
                //添加逻辑
                user.setEnable(BaseConstant.ISENABLE);
                user.setRole("1");
                user.setPassword(passwordEncoder.encode(user.getPassword()));
                String randomCode = RandomUtil.randomString(8);
                user.setUsername(StrUtil.isEmpty(user.getUsername())?randomCode:user.getUsername());
                user.setAccount(StrUtil.isEmpty(user.getAccount())?user.getEmail():user.getAccount());
                save(user);
                return user;
            } else {
                return dbUser;
            }
        }
    }

    public User doForget(User user) {
        User dbUser = new User();
        if (user.getPassword() == null) {
            throw new SelfException("不能将密码修改为空值！");
        } else {
            dbUser.setPassword(passwordEncoder.encode(user.getPassword()));
            if (user.getEmail() == null && user.getAccount() == null) {
                throw new SelfException("未查询到需要修改密码的对象");
            } else if (user.getEmail() != null) {
                dbUser.setEmail(user.getEmail());
            } else if (user.getAccount() != null) {
                dbUser.setAccount(user.getAccount());
            }
            baseMapper.saveOrUpdate(dbUser);
        }
        judgeUser(user);
        return user;
    }

    public String getUsernameById(Integer id) {
        User user = getById(id);
        return user.getUsername();
    }

    public String getUserMailById(Integer id) {
        return getById(id).getEmail();
    }

    private void judgeUser(User user) {
        if (ObjectUtil.isNull(user)) {
            throw new SelfException("404", "不存在此用户");
        }
        if (!user.judgeIsLocked()) {
            throw new SelfException("403", "该账户已被锁定");
        } else if (!user.judgeIsEnable()) {
            throw new SelfException("403", "该账户暂不可用，请激活注册或判断账户是否异常");
        }
    }

    @Override
    public UserDetails loadUserByUsername(String account) throws UsernameNotFoundException {
        User user = new User();
        if (account.contains("@")) {
            user.setEmail(account);
        } else {
            user.setAccount(account);
        }
        user = getOne(user);
        judgeUser(user);
        //此处需要获取用户所属角色的权限信息进行设置权限
        List<Role> roleList;
        ArrayList<String> permission = new ArrayList<>();

        //permission.add(user.getRole());
        //roleService.list().forEach(role -> permission.add(String.valueOf(role.getId())));
        //List<Auth> authList = authService.getByConditions(new Auth().setRoleId(Integer.valueOf(user.getRole())));
        //ArrayList<Integer> menuIds = new ArrayList<>();
        //authList.forEach(auth -> menuIds.add(auth.getMenuId()));
        //List<Menu> menuList = menuService.listByIds(menuIds);

        UserDetailImpl userDetail = new UserDetailImpl(user, permission);
        return userDetail;
    }

    public List<User> getUserHasMail(boolean judgeEnable){
        SelfQueryWrapper<User> wrapper = new SelfQueryWrapper<>();
        if (judgeEnable){
            wrapper.eq("enable",BaseConstant.ISENABLE);
        }else {
            wrapper.eq("enable",BaseConstant.DISABLE);
        }
        wrapper.isNotNull("email");
        return this.list(wrapper);
    }
}
